<template>
  <el-select
    class="select"
    v-model="warehouseId"
    value-key="id"
    clearable
    placeholder="请选择仓库列表"
    style="width: 200px"
    :disabled="disabled"
    :empty-values="['', null, undefined]"
    @change="warehouseChange"
  >
    <el-option v-for="item in warehouses" :key="item.id" :label="item.name" :value="item.id" />
  </el-select>
  <el-select
    class="select"
    v-model="warehouseAreaId"
    v-show="showWarehouseArea"
    value-key="id"
    clearable
    placeholder="请选择库区列表"
    style="width: 200px"
    :disabled="disabled"
    :empty-values="['', null, undefined]"
    @change="warehouseAreaChange"
  >
    <el-option v-for="item in warehouseAreas" :key="item.id" :label="item.name" :value="item.id" />
  </el-select>
  <el-select
    class="select"
    v-show="showWarehouseArea && showWarehouseSeat"
    v-model="warehouseSeatId"
    value-key="id"
    clearable
    placeholder="请选择库区列表"
    style="width: 200px"
    :disabled="disabled"
    :empty-values="['', null, undefined]"
    @change="emit('change')"
  >
    <el-option v-for="item in warehouseSeats" :key="item.id" :label="item.name" :value="item.id" />
  </el-select>
</template>
<script lang="ts" setup>
import urls from '@/api/request/urls';
import Request from '@/api/request/request';
import { nextTick, onMounted, ref, watch } from 'vue';
import type { Warehouse, WarehouseArea, WarehouseSeat } from '@/types/interface/wms_interface';
const emit = defineEmits(['change']);
// 获取父组件传递过来的值
interface Props {
  showWarehouseArea?: Boolean; //是否显示库区下拉框，如果不显示则库位也不显示
  showWarehouseSeat?: Boolean; //是否显示库位下拉框
  disabled?: Boolean; //组件是否不可用，只用于显示
}
const props = withDefaults(defineProps<Props>(), {
  showWarehouseArea: () => Boolean(true),
  showWarehouseSeat: () => Boolean(true),
  disabled: () => Boolean(false)
});
//定义选中的仓库id
const warehouseId = defineModel<string>('warehouseId', {
  required: false,
  default: ''
});
//定义选中的库区id
const warehouseAreaId = defineModel<string>('warehouseAreaId', {
  required: false,
  default: ''
});
//定义选中的库位id
const warehouseSeatId = defineModel<string>('warehouseSeatId', {
  required: false,
  default: ''
});
//定义仓库列表
const warehouses = ref<Warehouse[]>([]);
let warehouseSelectChange = false; //是否是本组件中的选项卡发生变化导致的转变。用于配合watch进行监听调试
//定义库区列表
const warehouseAreas = ref<WarehouseArea[]>([]);
let warehouseAreaSelectChange = false; //是否是本组件中的选项卡发生变化导致的转变。用于配合watch进行监听调试
//定义库位列表
const warehouseSeats = ref<WarehouseSeat[]>([]);
let warehouseSeatSelectChange = false; //是否是本组件中的选项卡发生变化导致的转变。用于配合watch进行监听调试
//获取仓库列表
const getWmsWarehouses = async () => {
  const resData: any = await new Request(urls.API_URL_BACKSTAGE_WMS_WMSWAREHOUSE + '/all').get();
  if (resData.success) {
    warehouses.value = resData.data;
  }
};
//获取库区列表（在某仓库下）
const getWmsWarehouseAreas = async (warehouseId: string) => {
  const resData: any = await new Request(urls.API_URL_BACKSTAGE_WMS_WMSWAREHOUSEAREA + '/all', {
    'warehouse.id': warehouseId
  }).get();
  if (resData.success) {
    warehouseAreas.value = resData.data;
  }
};
//获取库位列表（在某库区下）
const getWmsWarehouseSeats = async (areaId: string) => {
  const resData: any = await new Request(urls.API_URL_BACKSTAGE_WMS_WMSWAREHOUSESEAT + '/all', {
    'warehouseArea.id': areaId
  }).get();
  if (resData.success) {
    warehouseSeats.value = resData.data;
  }
};
//获取指定库区信息
const getWmsWarehouseArea = async (areaId: string): Promise<WarehouseArea | null> => {
  let warehouseArea = null;
  const resData: any = await new Request(`${urls.API_URL_BACKSTAGE_WMS_WMSWAREHOUSEAREA}/${areaId}`).get();
  if (resData.success) {
    warehouseArea = resData.data;
  }
  return warehouseArea;
};
//获取指定库位信息
const getWmsWarehouseSeat = async (seatId: string): Promise<WarehouseSeat | null> => {
  let warehouseSeat = null;
  const resData: any = await new Request(`${urls.API_URL_BACKSTAGE_WMS_WMSWAREHOUSESEAT}/${seatId}`).get();
  if (resData.success) {
    warehouseSeat = resData.data;
  }
  return warehouseSeat;
};
//当仓库下拉框发生变化时。包含清空
const warehouseChange = (warehouseId: string) => {
  //只要仓库发生了改变就清空库区列表
  warehouseAreaId.value = '';
  warehouseAreas.value.splice(0, warehouseAreas.value.length);
  //只要仓库发生了改变，就清空库位列表
  warehouseSeatId.value = '';
  warehouseSeats.value.splice(0, warehouseSeats.value.length);
  //如果选择了仓库
  if (warehouseId !== undefined && warehouseId !== null) {
    if (warehouseId.length > 0) {
      getWmsWarehouseAreas(warehouseId);
    }
  }
  emit('change');
};
//当库区下拉框发生变化时。包含清空
const warehouseAreaChange = (areaId: string) => {
  //只要库区发生了改变，就清空库位列表
  warehouseSeatId.value = '';
  warehouseSeats.value.splice(0, warehouseSeats.value.length);
  //如果选择了库区
  if (areaId !== undefined && areaId !== null) {
    if (areaId.length > 0) {
      getWmsWarehouseSeats(areaId);
    }
  }
  emit('change');
};
onMounted(() => {
  //获取仓库列表
  getWmsWarehouses();
});
//提供给父组件直接设置仓库的值
const setWarehouse = async (houseId: string) => {
  //清空库区列表
  warehouseAreaId.value = '';
  warehouseAreas.value.splice(0, warehouseAreas.value.length);
  //清空库位列表
  warehouseSeatId.value = '';
  warehouseSeats.value.splice(0, warehouseSeats.value.length);
  //读取仓库的信息
  const warehouse = await getWmsWarehouses();
  //最后重新赋值库区的值，这里是为了避免watch监听的warehouseId发生变化可能导致触发清空条件使得库区值变化（此处是指库区值被清空）
  warehouseId.value = houseId;
  //重新赋予库区的值，但是不选择，只是在下拉框列表显示。
  if (houseId !== undefined && houseId !== null) {
    if (houseId.length > 0) {
      getWmsWarehouseAreas(houseId);
    }
  }
};
//提供给父组件初始化库区的值
const setWarehouseArea = async (areaId: string) => {
  //读取库区的信息
  const warehouseArea = await getWmsWarehouseArea(areaId);
  if (warehouseArea !== undefined && warehouseArea != null) {
    warehouseId.value = warehouseArea.warehouse!.id!;
    //获取库区列表。因为这里设计到仓库重新赋值，所以会导致watch监听仓库的代码先执行完才转回这里继续执行
    await getWmsWarehouseAreas(warehouseArea.warehouse!.id!);
  }
  //最后重新赋值库区的值，这里是为了避免watch监听的warehouseId发生变化可能导致触发清空条件使得库区值变化（此处是指库区值被清空）
  warehouseAreaId.value = areaId;
  //设置库区相应的库位列表
  getWmsWarehouseSeats(areaId);
};
//提供给父组件初始化库位的值
const setWarehouseSeat = async (seatId: string) => {
  //读取库位的具体值
  const warehouseSeat = await getWmsWarehouseSeat(seatId);
  //设置库区的值
  //调用函数赋值仓库、库区的值
  setWarehouseArea(warehouseSeat?.warehouseArea?.id!);
  //设置选择的库位
  warehouseSeatId.value = seatId;
};
//如果传入的库位有初始值——20250428针对warehouseSeatId增加watch监听，因此取消此处
// if (warehouseSeatId.value != '') {
//   setWarehouseSeat(warehouseSeatId.value);
// }
//如果用于查询表单，在查询表单清空组件值时，也要手动进行清空
watch(
  () => warehouseId.value,
  (newVal: string | undefined, oldVal: string | undefined) => {
    if ((typeof newVal === 'undefined' || newVal === '') && typeof oldVal !== 'undefined' && oldVal.length > 0) {
      // 如果当前值不存在并且上一个值不为空，则说明在父组件被清空了（比如在查询表单中被重置按钮清空）
      //清空库区列表
      warehouseAreaId.value = '';
      warehouseAreas.value.splice(0, warehouseAreas.value.length);
      //清空库位列表
      warehouseSeatId.value = '';
      warehouseSeats.value.splice(0, warehouseSeats.value.length);
    }
  },
  { deep: true, immediate: true }
);
//监听库区变化
watch(
  () => warehouseAreaId.value,
  async (newVal: string | undefined, oldVal: string | undefined) => {
    if ((typeof newVal === 'undefined' || newVal === '') && typeof oldVal !== 'undefined' && oldVal.length > 0) {
      //如果不是库区下拉框发生变化。下面有两种情况
      //1.如果是库区被父组件清空（比如在查询表单中被重置按钮清空）
      //清空库位列表
      warehouseSeatId.value = '';
      warehouseSeats.value.splice(0, warehouseSeats.value.length);
      //2.20241013取消该判断，因为情况过于复杂，直接使用暴露父组件的方法进行复制
      //如果库区不为空，仓库是空，则说明库区的初始值是父组件直接赋予，因为正常的选择操作是先选择仓库，才到选择库区。
      // if (typeof newVal !== 'undefined' && newVal.length > 0 && (typeof warehouseId.value === 'undefined' || warehouseId.value.length === 0)) {
      //   console.log('监听,加载：' + newVal, warehouseId.value);
      //   //读取库区的信息
      //   await getWmsWarehouseArea(newVal);
      //   //获取库区列表。因为这里设计到仓库重新赋值，所以会导致watch监听仓库的代码先执行完才转回这里继续执行
      //   await getWmsWarehouseAreas(warehouseId.value);
      //   //此处需要重新赋值，原理不明。因为第一次赋值是newVal会重新变为空值，找不出是在哪里做了改变？20241007
      //   // warehouseAreaId.value = newVal;
      // }
    }
  },
  { deep: true, immediate: true }
);
//如果seat的值变化。
//注意，要考虑到仓库和库区发生变化时，库位会清空，这个时候库位不应该有动作；
//而如果是库位主动变化，在更新对应仓库和库区的值。这样设计主要是针对外部传入在其他库区的值时要发生变动。
watch(
  () => warehouseSeatId.value,
  (newVal: string | undefined, oldVal: string | undefined) => {
    if (typeof newVal !== 'undefined' && newVal !== '') {
      // 如果是主动切换库位
      //1.判断新库位是否与原库位在一个库区内。如果是则不更新库区和仓库
      let containsSeat = false;
      for (const warehouseSeatOfEach of warehouseSeats.value) {
        if (warehouseSeatOfEach.id == newVal) {
          containsSeat = true;
          break;
        }
      }
      //2.如果不包含库位，则更新库位
      if (!containsSeat) {
        setWarehouseSeat(newVal);
      }
    }
  },
  { deep: true, immediate: true }
);
//清空仓库选择列表
const reset = () => {
  //这里处理为空，然后通过watch自动重置所有
  warehouseId.value = '';
};
defineExpose({
  setWarehouse,
  setWarehouseArea,
  setWarehouseSeat,
  reset
});
</script>
<style lang="scss" scoped>
.select {
  margin-bottom: 3px;
  margin-right: 3px;
}
</style>
